package com.piece.admin.controller.monitor;

import com.piece.admin.controller.ControllerSupport;
import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.framework.enums.OptionType;
import com.piece.core.framework.support.dto.UserDetailDTO;
import com.piece.core.log.support.socket.LoggerMessage;
import com.piece.core.log.support.socket.LoggerQueue;
import com.piece.core.mongo.entity.MongoMessage;
import com.piece.core.mongo.service.MongoMessageService;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.time.DateUtil;
import com.piece.core.framework.util.async.AsyncManager;
import com.piece.core.web.constants.WsConstants;
import com.piece.module.flowable.dto.WfTask;
import com.piece.module.flowable.service.WfTaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@Api(tags = {"WebSocket管理"})
@RequestMapping(WsConstants.WS_PREFIX)
public class WebSocketController extends ControllerSupport {

    @Resource
    private SimpMessagingTemplate simpMessagingTemplate;

    @Resource
    private MongoMessageService mongoMessageService;

    @Resource
    private WfTaskService wfTaskService;

    private Map<String, ScheduledFuture> futureLogMap = new HashMap<>();

    private Map<String, ScheduledFuture> futureMessageMap = new HashMap<>();

    private Map<String, Long> futureMessageCount = new HashMap<>();

    private Map<String, ScheduledFuture> futureNoticeMap = new HashMap<>();

    private Map<String, Long> futureNoticeCount = new HashMap<>();

    private Map<String, ScheduledFuture> futureTaskMap = new HashMap<>();

    private Map<String, Long> futureTaskCount = new HashMap<>();

    @CrossOrigin
    @GetMapping("/startPollLog")
    @AclPermission(code = "system:log:view")
    @ApiOperation("查看实时日志信息")
    public AjaxResponse startPollLog(UserDetailDTO userDetail) {
        ScheduledFuture future = futureLogMap.get(userDetail.getId());
        if (null != future) {
            future.cancel(true);
        }

        // 设置日志读取状态
        LoggerQueue.getInstance().read();

        future = AsyncManager.getInstance().execute(new TimerTask() {
            @Override
            public void run() {
                LoggerMessage log = LoggerQueue.getInstance().poll();
                if (null != log) {
                    simpMessagingTemplate.convertAndSend(WsConstants.WS_TOPIC + "/pullLogger", log);
                }
            }
        }, 0, 1000, TimeUnit.MILLISECONDS);

        futureLogMap.put(userDetail.getId(), future);
        return success();
    }

    @CrossOrigin
    @GetMapping("/stopPollLog")
    @AclPermission(code = "system:log:view")
    @ApiOperation("停止查看实时日志信息")
    public AjaxResponse stopPollLog(UserDetailDTO userDetail) {
        // 设置日志非读取状态
        LoggerQueue.getInstance().unRead();

        ScheduledFuture future = futureLogMap.get(userDetail.getId());
        if (null != future) {
            future.cancel(false);
            futureLogMap.remove(userDetail.getId());
        }
        return success();
    }

    @CrossOrigin
    @GetMapping("/startPollMessage")
    @ApiOperation("实时查询系统信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "信息类别", allowableValues = "message,notify,task"),
            @ApiImplicitParam(name = "size", value = "获取数量")
    })
    public AjaxResponse startPollMessage(UserDetailDTO userDetail) {
        String type = Convert.toStr(getRequest().getParameter("type"),"message");
        OptionType optionType = OptionType.getByInfo(type);
        ScheduledFuture future = null;
        switch (optionType) {
            case MESSAGE:
                future = futureMessageMap.get(userDetail.getId());
                futureMessageCount.put(userDetail.getId(), 0L);
                break;
            case NOTICE:
                future = futureNoticeMap.get(userDetail.getId());
                futureNoticeCount.put(userDetail.getId(), 0L);
                break;
            case TASK:
                future = futureTaskMap.get(userDetail.getId());
                futureTaskCount.put(userDetail.getId(), 0L);
                break;
        }

        if (null == future) {
            final int size = Convert.toInt(getRequest().getParameter("size"), OptionType.MESSAGE.compareTo(optionType) == 1 ? 0 : 10);
            future = AsyncManager.getInstance().execute(new TimerTask() {
                @Override
                public void run() {
                    try {
                        long count = 0;
                        long count_now = 0;
                        switch (optionType) {
                            case MESSAGE:
                                count = futureMessageCount.get(userDetail.getId());
                                count_now = mongoMessageService.countMessageByUser(userDetail);
                                break;
                            case NOTICE:
                                count = futureNoticeCount.get(userDetail.getId());
                                count_now = mongoMessageService.countNotifyByUser(userDetail);
                                break;
                            case TASK:
                                count = futureTaskCount.get(userDetail.getId());
                                count_now = wfTaskService.countTodoProcess(userDetail.getId());
                                break;
                        }

                        if (count != count_now) {
                            switch (optionType) {
                                case MESSAGE:
                                    futureMessageCount.put(userDetail.getId(), count_now);
                                    List<MongoMessage> messages = queryMessage(userDetail, optionType, size);
                                    simpMessagingTemplate.convertAndSendToUser(userDetail.getId(), "/queue/getMessage", messages);
                                    break;
                                case NOTICE:
                                    futureNoticeCount.put(userDetail.getId(), count_now);
                                    List<MongoMessage> notifies = queryMessage(userDetail, optionType, size);
                                    simpMessagingTemplate.convertAndSendToUser(userDetail.getId(), "/queue/getNotify", notifies);
                                    break;
                                case TASK:
                                    futureTaskCount.put(userDetail.getId(), count_now);
                                    List<WfTask> tasks = queryTask(userDetail, size);
                                    simpMessagingTemplate.convertAndSendToUser(userDetail.getId(), "/queue/getTask", tasks);
                                    break;
                            }
                        }
                    } catch (MessagingException e) {
                        log.error(e.getMessage());
                    }
                }
            }, 500, 60000, TimeUnit.MILLISECONDS);

            switch (optionType) {
                case MESSAGE:
                    futureMessageMap.put(userDetail.getId(), future);
                    break;
                case NOTICE:
                    futureNoticeMap.put(userDetail.getId(), future);
                    break;
                case TASK:
                    futureTaskMap.put(userDetail.getId(), future);
                    break;
            }
        }
        return success();
    }

    private List<MongoMessage> queryMessage(UserDetailDTO userDetail, OptionType optionType, int size) {
        List<MongoMessage> messages = mongoMessageService.findUserMessage(userDetail, optionType.getCode(), size);
        for (MongoMessage message : messages) {
            message.setTimeBefore(DateUtil.getDescriptionTimeFromTimestamp(message.getStartTime().getTime()));
        }
        return messages;
    }

    private List<WfTask> queryTask(UserDetailDTO userDetail, int size) {
        return wfTaskService.findTodoList(userDetail.getId(), size);
    }

    @CrossOrigin
    @GetMapping("/stopPollMessage")
    @ApiOperation("停止查询系统信息")
    @ApiImplicitParam(name = "type", value = "消息类别", allowableValues = "message,notify,mobile,task")
    public AjaxResponse stopPollMessage(UserDetailDTO userDetail) {
        String type = Convert.toStr(getRequest().getParameter("type"),"message");
        OptionType optionType = OptionType.getByInfo(type);
        ScheduledFuture future;
        switch (optionType) {
            case MESSAGE:
                future = futureMessageMap.get(userDetail.getId());
                if (null != future) {
                    future.cancel(false);
                    futureMessageCount.remove(userDetail.getId());
                    futureMessageMap.remove(userDetail.getId());
                }
                break;
            case NOTICE:
                future = futureNoticeMap.get(userDetail.getId());
                if (null != future) {
                    future.cancel(false);
                    futureNoticeCount.remove(userDetail.getId());
                    futureNoticeMap.remove(userDetail.getId());
                }
                break;
            case TASK:
                future = futureTaskMap.get(userDetail.getId());
                if (null != future) {
                    future.cancel(false);
                    futureTaskCount.remove(userDetail.getId());
                    futureTaskMap.remove(userDetail.getId());
                }
                break;
        }
        return success();
    }
}
